﻿using System.Buffers;

namespace ConsoleApp;

/// <summary>
/// ArrayPool<T> 是一个提供对象池功能的类，用于重用数组实例以减少内存分配和垃圾回收的开销。当你需要频繁地创建和销毁大量相同大小的数组时，使用 ArrayPool<T> 可以显著提高性能。
/// ArrayPool<T> 类提供了以下方法：
/// Shared：这是一个静态属性，返回一个共享的 ArrayPool<T> 实例，可以在整个应用程序中重用。
/// Get：从池中获取一个适当大小的数组，如果池中没有适当大小的数组，则会创建一个新的数组。
/// Return：将数组返回给池，以便以后重用。
/// 使用 ArrayPool<T> 的一个常见场景是在处理网络数据流或文件I/O时，你可能需要读取或写入固定大小的缓冲区。通过重用这些缓冲区，你可以避免频繁的数组创建和销毁操作。
/// ArrayPool<T> 是 .NET 提供的用于管理数组租借和归还的内存池。它使用分区锁（分段锁）而不是 Concurrent 集合，主要原因包括性能优化和资源管理的需求
/// </summary>
/// <typeparam name="T"></typeparam>
public class DemoArrayPool<T>
{
    private readonly object[] _locks;
    private readonly List<T[]>[] _arrays;
    private readonly int _partitions;

    static void Main()
    {
        // 获取一个共享的ArrayPool<byte>实例
        var pool = ArrayPool<byte>.Shared;

        // 从池中获取一个256字节的数组
        var buffer = pool.Rent(256);

        try
        {
            // 在这里使用buffer
            // 例如，从网络流或文件中读取数据到buffer中

            // ...

            // 使用完buffer后，将其返回给池
        }
        finally
        {
            // 总是确保在finally块中返回buffer给池
            pool.Return(buffer);
        }

        // 继续执行其他操作...
    }
    
    public DemoArrayPool(int partitions)
    {
        _partitions = partitions;
        _locks = new object[partitions];
        _arrays = new List<T[]>[partitions];
        for (var i = 0; i < partitions; i++)
        {
            _locks[i] = new object();
            _arrays[i] = new List<T[]>();
        }
    }

    private int GetPartitionIndex(int length)
    {
        return (length.GetHashCode() & int.MaxValue) % _partitions;
    }

    public T[] Rent(int length)
    {
        var index = GetPartitionIndex(length);
        lock (_locks[index])
        {
            if (_arrays[index].Count <= 0) return new T[length];
            var array = _arrays[index][_arrays[index].Count - 1];
            _arrays[index].RemoveAt(_arrays[index].Count - 1);
            return array;
        }
    }

    public void Return(T[] array)
    {
        int index = GetPartitionIndex(array.Length);
        lock (_locks[index])
        {
            _arrays[index].Add(array);
        }
    }
// 场景一: 大量数据处理
    // static void Main(string[] args){    var pool = ArrayPool<byte>.Shared;
    //     Parallel.For(0, 100, (i) =>    {        var buffer = pool.Rent(1024); // 为每个任务租用一个1KB的数组
    //         try        {            // 执行并发任务            PerformTask(buffer, (byte)i);
                // 打印每个任务处理的数组的前5个字节            Console.WriteLine($"Task {i}: [{string.Join(", ", buffer[0..5])}]");        }        finally        {            pool.Return(buffer, clearArray: false);        }    });}
// 定义执行并发任务的方法static void PerformTask(byte[] buffer, byte taskId){    // 将数组的每个字节设置为当前任务的编号    for (int i = 0; i < buffer.Length; i++)    {        buffer[i] = taskId;    }}
    
// 场景二：高并发环境 
    
// 场景三：IO操作缓冲
//     static void Main(string[] args){    var pool = ArrayPool<byte>.Shared;    var buffer = pool.Rent(4096); // 租用一个4KB的数组作为缓冲区
//         try    {        using (var stream = new FileStream("./example.txt", FileMode.Open))        {            int bytesRead;            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)            {                // 处理读取的数据                ProcessBufferData(buffer, bytesRead);            }        }    }    finally    {        pool.Return(buffer, clearArray: false);    }}
// // 定义处理读取的数据的方法static void ProcessBufferData(byte[] buffer, int bytesRead){    // 将字节转换为字符串    string text = Encoding.UTF8.GetString(buffer, 0, bytesRead);
//             // 打印到控制台    Console.WriteLine(text);}
}